package com.cmcc.cmii.cmiiservicemanagement.config;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.cmcc.cmii.cmiiservicemanagement.model.ServiceDefinition;
import com.cmcc.cmii.cmiiservicemanagement.utils.RequestUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import reactor.core.scheduler.Schedulers;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Thanks
 */
@Configuration
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class ServiceHealthIndicator {
    private final ServiceProperties serviceProperties;
    private final RequestUtils requestUtils;

    private final ServiceDiscoveryClient serviceDiscoveryClient;

    private final HealthCheckConfig healthCheckConfig;


    public void check(){
        Schedulers.single().schedulePeriodically(()->{
            checkServiceHealth();
        },0,healthCheckConfig.getPeriod(), TimeUnit.SECONDS);
    }



    private void checkServiceHealth(){
        List<ServiceDefinition> services = serviceProperties.getServices();
        if(!CollectionUtils.isEmpty(services)){
            Integer httpStatus = HttpStatus.OK.value();
            for (int i = 0; i < services.size(); i++) {
                ServiceDefinition serviceDefinition = services.get(i);
                Instance instance = new Instance();
                instance.setServiceName(serviceDefinition.getServiceName());
                instance.setIp(serviceDefinition.getIp());
                instance.setPort(serviceDefinition.getPort());
                instance.getMetadata().put("secure",serviceDefinition.getIsHttps());
                try{
                    String healthCheckUrl = serviceDefinition.getHealthCheckUrl();
                    if(StringUtils.isBlank(healthCheckUrl)){
                        log.info("Health check success. register this instance. applicationName = {}, ip = {}, port = {}",
                                serviceDefinition.getServiceName(), serviceDefinition.getIp(), serviceDefinition.getPort()
                        );

                        serviceDiscoveryClient.registerInstance(serviceDefinition.getServiceName(),instance);
                        continue;
                    }
                    String checkReqMethod = serviceDefinition.getCheckReqMethod();
                    Map<String, Object> checkReqHeader = serviceDefinition.getCheckReqHeader();
                    Map<String, Object> checkReqBody = serviceDefinition.getCheckReqBody();
                    Map<String, Object> checkRespParam = serviceDefinition.getCheckRespParam();
                    ResponseEntity<String> responseEntity = requestUtils.sendRequest(healthCheckUrl, checkReqMethod, checkReqHeader, checkReqBody);
                    int status = responseEntity.getStatusCode().value();
                    if(!httpStatus.equals(status)){
                        log.error("Health check failed. unregister this instance. applicationName = {}, ip = {}, port = {}",
                                serviceDefinition.getServiceName(), serviceDefinition.getIp(), serviceDefinition.getPort()
                        );
                        serviceDiscoveryClient.deregisterInstance(serviceDefinition.getServiceName(),serviceDefinition.getIp(),serviceDefinition.getPort());
                        continue;
                    }
                    if(CollectionUtils.isEmpty(checkRespParam)){
                        log.info("Health check success. register this instance. applicationName = {}, ip = {}, port = {}",
                                serviceDefinition.getServiceName(), serviceDefinition.getIp(), serviceDefinition.getPort()
                        );
                        serviceDiscoveryClient.registerInstance(serviceDefinition.getServiceName(),instance);
                        continue;
                    }
                    String body = responseEntity.getBody();
                    Map map = JSONObject.parseObject(body, Map.class);
                    boolean flag = false;
                    for(String key:checkRespParam.keySet()){
                        if(!map.containsKey(key)){
                            log.error("Health check failed. unregister this instance. applicationName = {}, ip = {}, port = {}",
                                    serviceDefinition.getServiceName(), serviceDefinition.getIp(), serviceDefinition.getPort()
                            );
                            serviceDiscoveryClient.deregisterInstance(serviceDefinition.getServiceName(),serviceDefinition.getIp(),serviceDefinition.getPort());
                            flag = true;
                            break;
                        }
                    }
                    if(!flag){
                        log.info("Health check success. register this instance. applicationName = {}, ip = {}, port = {}",
                                serviceDefinition.getServiceName(), serviceDefinition.getIp(), serviceDefinition.getPort()
                        );
                        serviceDiscoveryClient.registerInstance(serviceDefinition.getServiceName(),instance);
                    }

                }catch (Exception e){
                    e.printStackTrace();
                    log.error("Health check failed. unregister this instance. applicationName = {}, ip = {}, port = {}",
                            serviceDefinition.getServiceName(), serviceDefinition.getIp(), serviceDefinition.getPort()
                    );
                    serviceDiscoveryClient.deregisterInstance(serviceDefinition.getServiceName(),serviceDefinition.getIp(),serviceDefinition.getPort());
                }

            }
        }
    }


}
